<?php

namespace App\Models;

use app\common\model\ReservationApplyModel;
use app\common\model\ReservationScheduleModel;
use app\common\model\ReservationSpecialScheduleModel;
use App\Http\Controllers\Controller;
use App\Http\Controllers\ScoreRuleController;
use Exception;
use http\Env\Request;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache;

/**
 * 文化配送物品预约表
 * Class ReservationModel
 * @package app\common\model
 */
class Reservation extends BaseModel
{
    use HasFactory;

    const CREATED_AT = 'create_time';
    const UPDATED_AT = 'change_time';

    public $table = 'reservation';

    /**
     * 预约种类
     */
    public function reservationNode()
    {
        $data = [
            ['node' => 5, 'name' => '到馆预约', 'intro' => '快速预约，及时到馆'],
            ['node' => 6, 'name' => '座位预约', 'intro' => '快速预约，及时签到'],
            ['node' => 999, 'name' => '空间预约', 'intro' => '24小时无人值守'],

            ['node' => 1, 'name' => '师资预约', 'intro' => '线下培训，面对面教学'],
            ['node' => 2, 'name' => '设备预约', 'intro' => '快速预约，现场使用'],
            ['node' => 3, 'name' => '教室预约', 'intro' => '快速预约，多人使用'],
            ['node' => 4, 'name' => '展览预约', 'intro' => '文艺展览，预约参观'],
            ['node' => 7, 'name' => '储物柜预约', 'intro' => '线上预约，线下领取'],
        ];
        return $data;
    }

    /**
     * 获取行为类型
     */
    public function getBehaviorType($node)
    {
        if (empty($node)) {
            return 4;
        }
        switch ($node) {
            case 1:
                $type = 6;
                break;
            case 2:
                $type = 7;
                break;
            case 3:
                $type = 8;
                break;
            case 4:
                $type = 9;
                break;
            case 5:
                $type = 3;
                break;
            case 6:
                $type = 4;
                break;
            case 7:
                $type = 31;
                break;
            default:
                $type = 4;
        }
        return $type;
    }

    /**
     * 关联配送申请
     */
    public function conApply()
    {
        return $this->hasMany(ReservationApply::class, 'reservation_id', 'id');
    }


    /**
     * 关联文化配送排班信息
     */
    public function conSchedule()
    {
        return $this->hasMany(ReservationSchedule::class, 'reservation_id', 'id');
    }

    /**
     * 用户预约报名填写信息
     */
    public static function getReservationApplyParam()
    {
        return [
            ['id' => 5, 'field' => 'img', 'value' => '头像'],
            ['id' => 1, 'field' => 'username', 'value' => '姓名'],
            ['id' => 2, 'field' => 'id_card', 'value' => '身份证'],
            ['id' => 8, 'field' => 'sex', 'value' => '性别'], //性别
            ['id' => 9, 'field' => 'age', 'value' => '年龄'], //年龄
            ['id' => 3, 'field' => 'tel', 'value' => '电话号码'],
            ['id' => 4, 'field' => 'reader_id', 'value' => '读者证'],
            ['id' => 7, 'field' => 'unit', 'value' => '单位名称'], //单位名称
            ['id' => 6, 'field' => 'remark', 'value' => '备注'], //备注  最多100字
            //  ['id' => 10, 'field' => 'accessory', 'value' => '附件'], //压缩包  最大3M
        ];
    }

    /**
     * 检查预约报名填报信息
     * @param array $act_info 活动信息
     * @param array $real_info
     * @param $data 需要验证的真实信息id用|连接起来    1、姓名   2 、身份证号码  3、电话号码   4、读者证号码    5、真实人物头像   6、备注  7 单位名称 8 性别 9 年龄  10、附件
     * @return array
     */
    public function checkApplyParam($res_info, array $real_info, array $data)
    {
        $where = [];
        foreach ($real_info as $key => $val) {
            if ($val == 1) {
                if (empty($data['username']) || mb_strlen($data['username']) < 2) {
                    throw new Exception('用户名规则不正确');
                } else {
                    $where['username'] = $data['username'];
                }
            } elseif ($val == 2) {
                if (empty($data['id_card']) || !is_legal_no($data['id_card'])) {
                    throw new Exception('身份证号码规则不正确');
                } else {
                    $where['id_card'] = $data['id_card'];
                }
            } elseif ($val == 3) {
                if (empty($data['tel']) || !verify_tel($data['tel'])) {
                    throw new Exception('电话号码规则不正确');
                } else {
                    $where['tel'] = $data['tel'];
                }
            } elseif ($val == 4) {
                if (empty($data['reader_id'])) {
                    throw new Exception('读者证不能为空');
                } else {
                    $where['reader_id'] = $data['reader_id'];
                }
            } elseif ($val == 5) {
                if (empty($data['img'])) {
                    throw new Exception('头像不能为空');
                } else {
                    $where['img'] = $data['img'];
                }
            } elseif ($val == 6) {
                // if (empty($data['remark'])) {
                //     throw new Exception('备注不能为空');
                // } else {
                $where['remark'] = addslashes($data['remark']); //备注可为空
                // }
            } elseif ($val == 7) {
                if (empty($data['unit'])) {
                    throw new Exception('单位不能为空');
                } else {
                    $where['unit'] = $data['unit'];
                }
            } elseif ($val == 8) {
                if (empty($data['sex']) || ($data['sex'] != 1 && $data['sex'] != 2)) {
                    throw new Exception('性别规则不正确');
                } else {
                    $where['sex'] = $data['sex'];
                }
            } elseif ($val == 9) {
                if (empty($data['age']) || !is_numeric($data['age']) || $data['age'] > 100) {
                    throw new Exception('年龄规则不正确');
                } else {
                    $where['age'] = $data['age'];
                }
            }
        }
        //判断年龄和性别是否符合要求
        if ($res_info['start_age'] || $res_info['end_age']) {
            $age = !empty($data['age']) ? $data['age'] : get_user_age_by_id_card($data['id_card']);

            if ($res_info['start_age'] && $res_info['start_age'] > $age) {
                throw new Exception('年龄不符合要求');
            }
            if ($res_info['end_age'] && $res_info['end_age'] < $age) {
                throw new Exception('年龄不符合要求');
            }
        }
        if ($res_info['astrict_sex'] && ($res_info['astrict_sex'] == 1 || $res_info['astrict_sex'] == 2)) {
            $sex = !empty($data['sex']) ? $data['sex'] : get_user_sex_by_id_card($data['id_card']);

            if ($res_info['astrict_sex'] != $sex) {
                throw new Exception('性别不符合要求');
            }
        }


        return $where;
    }

    /**
     * 处理预约参数
     * $data 管理员输入的活动信息
     */
    public function disRealInfo($data)
    {
        $is_real = $data['is_real'];
        $real_info = $data['real_info'];
        $real_info_arr = explode('|', $real_info);
        if ($data['astrict_sex'] && ($data['astrict_sex'] == 1 || $data['astrict_sex'] == 2)) {
            $is_real = 1;
            if (!in_array(2, $real_info_arr) && !in_array(8, $real_info_arr)) {
                $real_info .= "|8";
            }
        }
        if ($data['start_age'] || $data['end_age']) {
            $is_real = 1;
            if (!in_array(2, $real_info_arr) && !in_array(9, $real_info_arr)) {
                $real_info .= "|9";
            }
        }
        $real_info = trim($real_info, '|');
        return [$is_real, $real_info];
    }

    /**
     * 预约列表
     * @param node int 分类  1  人物    2  物品    3 教室   4 展览预约    5 到馆预约 6 座位预约 7 储物柜预约
     * @param limit int 分页大小
     * @param keywords string 搜索筛选
     * @param start_time string 开始时间
     * @param end_time string 结束时间
     * @param is_play string 是否发布 0 所有  是否发布  1.发布  2.未发布  默认2
     */
    public function lists($field = null, $node = 0, $keywords = null, $start_time = null, $end_time = null, $is_play = 0, $limit = 10)
    {

        if (empty($field)) {
            $field = [
                'id', 'node', 'img', 'name', 'astrict_sex', 'kind', 'type_tag', 'number', 'apply_number', 'intro', 'province',
                'city', 'district', 'street', 'address', 'unit', 'contacts', 'tel', 'is_play', 'is_real', 'real_info', 'sign_way', 'create_time'
            ];
        }
        $res = $this->select($field)
            ->where(function ($query) use ($keywords) {
                if ($keywords) {
                    $query->where('name', 'like', "%$keywords%");
                }
            })->where(function ($query) use ($node, $start_time, $end_time, $is_play) {
                if ($node) {
                    $query->where('node', $node);
                }
                if ($is_play) {
                    $query->where('is_play', $is_play);
                }
                if ($start_time && $end_time) {
                    $query->whereBetween('create_time', [$start_time, $end_time]);
                }
            })
            ->where('is_del', 1)
            ->orderByDesc('id')
            ->paginate($limit)
            ->toArray();

        $reservationSeatModel = new ReservationSeat();
        $reservationApplyModel = new ReservationApply();
        foreach ($res['data'] as $key => $val) {
            $res['data'][$key]['type_tag'] = !empty($val['type_tag']) ? explode("|", $val['type_tag']) : [];
            $res['data'][$key]['intro'] = str_replace('&nbsp;', '', strip_tags($val['intro']));
            if ($val['node'] == 6) {
                //增加返回座位数量
                $seat_num = $reservationSeatModel->seatList($val['id'], 1);
                $res['data'][$key]['seat_number'] = count($seat_num);
            }
            if ($val['node'] == 7) {
                $reservationApplyModel = new ReservationApply();
                $number = $reservationApplyModel->getCabinetApplyNumber($val['id']);
                $res['data'][$key]['apply_number'] = $number; //当前预约数量
            }

            //获取总预约次数
            $res['data'][$key]['total_apply_number'] = $reservationApplyModel->getMakeNumber($val['id'], [1, 3, 5, 6, 7]);
        }
        return $res;
    }
    /**
     * 预约详情
     */
    public function detail($id, $field = null)
    {
        if (empty($field)) {
            $field = [
                'id', 'node', 'display_day', 'kind', 'unit', 'name', 'img', 'intro', 'type_tag', 'number', 'province', 'city',
                'district', 'street', 'address', 'apply_number', 'contacts', 'tel', 'start_age', 'end_age', 'is_reader', 'lon', 'lat',
                'is_cancel', 'is_approval', 'day_make_time', 'is_real', 'real_info', 'make_max_num', 'sign_way', 'education', 'clock_time',
                'return_time'
            ];
        }
        $data = $this->select($field)->find($id);

        //重置个数
        if ($data['node'] == 6 || $data['node'] == 7) {
            $reservationSeatModel = new ReservationSeat();
            $number = $reservationSeatModel->seatList($id, 1);
            $data['number'] = count($number);
        }

        $reservationApplyModel = new ReservationApply();
        if ($data['node'] == 7) {
            $number = $reservationApplyModel->getCabinetApplyNumber($id);
            $data['apply_number'] = $number; //当前预约数量
        }
        //获取总预约次数
        $data['total_apply_number'] = $reservationApplyModel->getMakeNumber($data['id'], [1, 3, 5, 6, 7]);

        return $data;
    }


    /**
     * 判断某个活动是否有人报名
     */
    public function resIsMake($id)
    {
        $apply_status = ReservationApply::where('reservation_id', $id)
            ->where(function ($query) {
                $query->whereIn("status", [1, 3, 6, 7]);
            })->first();
        return $apply_status ? true : false;
    }


    /**
     * 获取预约时间 和当前产品是否可以预约
     */
    public function getMakeTime($user_id = null, $reservation_info, $display_day = 7)
    {
        $week_time = get_continuous_week_time(true, $display_day); //获取未来一周的日期和星期几
        //获取所有的预约时间 可预约时间段
        $reservationApplyModel = new ReservationApply();
        $reservationScheduleModel = new ReservationSchedule();
        $reservationSpecialScheduleModel = new ReservationSpecialSchedule();
        $index = 0;
        foreach ($week_time as $key => $val) {
            //先查看是有没特殊日期时间
            $special_info = $reservationSpecialScheduleModel->getSpecialListByDate($reservation_info['id'], $val['date']);
            if ($special_info && count($special_info) == 1 && empty($special_info[0]['start_time']) && empty($special_info[0]['end_time'])) {
                continue; //当前不支持预约
            }

            $make_list[$index]['date'] = date("Y/m/d", strtotime($val['date']));
            $make_list[$index]['week'] = $val['week'];

            $i = 0;
            $is_make = true; //true 表示已预约，不能预约
            $is_self_make = true; //true 表示自己已预约，不能预约
            $make_list[$index]['quantum'] = null;

            if ($special_info) {
                $schedule_type = 2;
                $schedule_info = $special_info; // 特殊时间
            } else {
                //查询是否有排版时间
                $schedule_info = $reservationScheduleModel->getScheduleList($reservation_info['id'], $val['weeks']);
                $schedule_type = 1;
            }
            if (!empty($schedule_info)) {
                $can_make_num = 0;
                $can_self_make_num = 0;
                foreach ($schedule_info as $k => $v) {
                    $temp_temp = $reservationApplyModel->getScheduleDetail($user_id, $reservation_info, $v, $val['date'], $schedule_type);
                    $make_list[$index]['quantum'][$i] = $temp_temp;
                    $i++;
                    if (!$temp_temp['is_make']) $can_make_num++;
                    if ($temp_temp['is_self_make']) $can_self_make_num++;
                }
                $is_make = $can_make_num > 0 ? false : true; //总的状态
                $is_self_make = $is_make && $can_self_make_num > 0 ? true : false; //总的状态
            }

            $make_list[$index]['is_make'] = $is_make; //总的状态
            $make_list[$index]['is_self_make'] = $is_self_make; //总的状态
            $index++;
        }
        return $make_list;
    }

    /**
     * 预约，查询逾期未签到用户，将状态改为已逾期，并且空出座位
     */
    public function checkApplyStatus()
    {
        $reservationApply = new ReservationApply();
        $res = $reservationApply->from($reservationApply->getTable() . ' as a')
            ->select('a.id', 'a.reservation_id', 'r.name', 'a.status', 'a.is_violate', 'a.user_id', 'a.account_id', 'a.score', 'a.expire_time', 'r.node', 'r.is_sign')
            ->join('reservation as r', 'r.id', '=', 'a.reservation_id')
            ->where('expire_time', '<', date('Y-m-d H:i:s', strtotime('-1 min')))
            //   ->where('r.is_sign', 1)
            //->whereIn('r.node', [3, 5, 6]) //全部可以逾期
            ->whereIn('a.status', [1, 3])
            ->get();

        $controllerObj = new Controller();
        foreach ($res as $key => $val) {
            if ($val['node'] != 7 && $val['is_sign'] != 1) {
                continue;
            }
            if ($val['is_violate'] == 1) {
                $val->is_violate = 2; //自动违规
                $val->violate_reason = $val['node'] != 7 ? '逾期未签到' : '逾期未领取'; //自动违规
                $val->violate_time = $val->expire_time;

                $system_id = $controllerObj->systemAdd('预约已违规', $val->user_id, $val->account_id, 33, $val->id, '您申请的预约：【' . $val->name . '】' . $val->violate_reason . '，自动违规', $val->expire_time);
                Cache::pull('violate_number'); //重置违规次数
                //  $userInfoObj->where('id', $val['user_id'])->increment('reservation_violate_num'); //增加违规次数
            }
            $val->status = 5; //并改为过期
            $val->save();

            /**退还积分 （过期未签到，暂时不返还积分，根据需求修改）*/
            // if (!empty($val['score'])) {
            //     $score_rule = new ScoreRuleController();
            //     $score_msg = $score_rule->getScoreMsg($val['score']);
            //     $score_rule->scoreReturn(5, $val['score'],$val['user_id'], $val['account_id'], '您申请的预约：【' . $val['name'] . '】未按时签到，' . $score_msg . ' ' . abs($val['score']) . ' 积分',$system_id);
            // }
        }
    }

    /**
     * 判断是否有其他预约
     * @param  $node  int 分类  0全部  1  人物    2  物品    3 教室   4 展览预约    5 到馆预约 6 座位预约  7 储物柜预约
     */
    public function isExistsOtherMake($user_id, $weeks, $node = [])
    {
        //查看指定日期是否有特殊时间设置
        $reservationSpecialScheduleModel = new ReservationSpecialSchedule();
        $reservation_schedule = $reservationSpecialScheduleModel->getSpecialScheduleInfo(null, date('Y-m-d'));
        //默认特殊
        if (!empty($reservation_schedule)) {
            $apply = $this->getScheduleInfoApplyData($user_id, 2, $reservation_schedule, $node);
            if ($apply) {
                return $apply;
            }
        }
        //2类排版单独计算，因为可能存在有些有特殊排版，有些只有普通排版
        $reservationScheduleModel = new ReservationSchedule();
        $reservation_schedule = $reservationScheduleModel->getWeekScheduleInfo(null, $weeks);
        if (!empty($reservation_schedule)) {
            $apply = $this->getScheduleInfoApplyData($user_id, 1, $reservation_schedule, $node);
            if ($apply) {
                return $apply; //返回排班时间
            }
        }

        if (in_array(7, $node)) {
            $apply = $this->getCabinetApplyData($user_id);
            if ($apply) {
                return $apply;
            }
        }
        return false;
    }

    /**
     * 获取排版报名数据（此方法对于储物柜预约不适用）
     */
    public function getScheduleInfoApplyData($user_id, $schedule_type, $reservation_schedule, $node)
    {
        $reservationApplyModel = new ReservationApply();
        foreach ($reservation_schedule as $key => $val) {
            $apply = $reservationApplyModel->select('a.id as apply_id', 'r.id', 'r.node', 'a.expire_time', 'a.status')
                ->from('reservation_apply as a')
                ->join('reservation as r', 'r.id', '=', 'a.reservation_id')
                ->where(function ($query) use ($node) {
                    if ($node) {
                        $query->whereIn('r.node', $node);
                    }
                })
                ->where('a.user_id', $user_id)
                ->where('schedule_type', $schedule_type)
                ->where('schedule_id', $val['id'])
                ->whereIn('a.status', [1, 6])
                ->where('a.expire_time', '>', date('Y-m-d H:i:s'))
                ->first();
            if ($apply) {
                $apply['start_time'] = $val['start_time'];
                $apply['end_time'] = $val['end_time'];
                return $apply;
            }
        }
        return [];
    }
    /**
     * 获取排版报名数据（针对储物柜预约不适用）
     */
    public function getCabinetApplyData($user_id)
    {
        $reservationApplyModel = new ReservationApply();
        $apply = $reservationApplyModel->select('a.id as apply_id', 'r.id', 'r.node', 'a.expire_time', 'a.status', 'a.create_time', 'a.return_expire_time')
            ->from('reservation_apply as a')
            ->join('reservation as r', 'r.id', '=', 'a.reservation_id')
            ->where('node', 7)
            ->where('a.user_id', $user_id)
            ->whereIn('a.status', [1, 6])
            ->where('a.expire_time', '>', date('Y-m-d H:i:s'))
            ->first();
        if ($apply) {
            $apply['start_time'] = $apply['create_time'];
            $apply['end_time'] = $apply['return_expire_time'];
            return $apply;
        }
        return [];
    }

    /**
     * 获取座位预约大数据信息
     */
    public function getSeatReservationWallInfo($reservation_id = null)
    {
        //获取座位总数
        $reservation_info = $this->select('id', 'name', 'number', 'province', 'city', 'district', 'street', 'address')
            ->where('node', 6)
            ->where('is_del', 1)
            ->where('is_play', 1)
            ->where(function ($query) use ($reservation_id) {
                if ($reservation_id) {
                    $query->where('id', $reservation_id);
                }
            })
            ->get()
            ->toArray();
        if (empty($reservation_info)) {
            return [null, null, null];
        }
        $reservation_id_arr = array_column($reservation_info, 'id');
        $address = $reservation_info[0]['province'] . $reservation_info[0]['city'] . $reservation_info[0]['district'] . $reservation_info[0]['street'] . $reservation_info[0]['address'];
        // $number = ReservationSeat::whereIn('reservation_id' , $reservation_id_arr)->where('is_del', 1)->where('is_play', 1)->count();//计算座位数量

        //固定返回个数
        $number = 28;
        return [$reservation_id_arr, $number, $address];
    }

    /**
     * 获取预约名称
     * @param node 0全部  1  人物    2  物品    3 教室   4 展览预约    5 到馆预约 6 座位预约 7储物柜预约
     */
    public function getNodeName($node)
    {
        $data = ['1' => '人物预约', '物品', '教室', '展览预约', '到馆预约', '座位预约', '储物柜预约'];
        return $data[$node];
    }
}
